package com.smday.stack;

import org.omg.CORBA.PRIVATE_MEMBER;

import java.security.PublicKey;
import java.util.*;

/**
 * @author Summerday
 */
public class PolandNotation {


    public static void main(String[] args) {


        //中缀表达式-->后缀表达式 1+((2+3)*4)-5 ==> 1 2 3 + 4 * + 5 -

        //直接对str进行操作不方便,先将中缀表达式 放入list

        String exp = "1+((2+3)*4)-5";
        List<String> list = toInfixExperList(exp);
        System.out.printf("中缀表达式 ==> %s\n", list);

        //中缀表达式的list ==> 后缀表达式的list    1 2 3 + 4 * + 5 -

        List<String> list1 = parseSuffixExperList(list);
        System.out.printf("后缀表达式 ==> %s\n", list1);


        System.out.printf("最后结果为 ==> %s\n", calculate(list1));


    }

    public static List<String> parseSuffixExperList(List<String> ls) {

        //定义两个栈

        //符号栈
        Stack<String> s1 = new Stack<>();

        //第二个栈没有pop操作,而且需要逆序,直接使用List<String> s2
        List<String> s2 = new ArrayList<>();

        //遍历ls,从左至右扫描中缀表达式
        for (String s : ls) {

            //如果是一个数,加入s2
            if (s.matches("\\d+")) {
                s2.add(s);
            } else if ("(".equals(s)) {
                //左括号直接入s1
                s1.add(s);
            } else if (")".equals(s)) {

                //如果是右括号,依次弹出s1栈顶的运算符,放入s2,直到遇到(为止
                while (!"(".equals(s1.peek())) {
                    s2.add(s1.pop());
                }
                //消除小括号
                s1.pop();
            } else {

                while (s1.size() != 0 && !"(".equals(s1.peek()) && Operation.getValue(s1.peek()) <= Operation.getValue(s)) {
                    //将s1栈顶的运算符弹出,并压入s2,再次进行比较,也就是循环
                    s2.add(s1.pop());
                }
                ////当s1栈顶运算符的优先级<=栈顶运算符的优先级 s1为空或者遇到s1的栈顶为(或者当前的优先级>栈顶运算符优先级,将s压入栈
                s1.push(s);
            }

        }
        //将s1中剩余的运算符依次弹出并加入s2
        while (s1.size() != 0) {
            s2.add(s1.pop());
        }
        return s2;

    }


    //判断字符是否为数字
    public static boolean isNumber(char c) {

        return c >= 48 && c <= 57;

    }

    //将中缀转List
    public static List<String> toInfixExperList(String s) {

        List<String> ls = new ArrayList<String>();

        int index = 0;
        //多位数的拼接
        StringBuilder str = new StringBuilder("");

        //没遍历到一个字符,就放入c
        char c;
        do {
            c = s.charAt(index);
            if ((!isNumber(c))) {
                ls.add("" + c);
                index++;
            } else {

                while (index < s.length() && isNumber(s.charAt(index))) {
                    str = new StringBuilder();
                    c = s.charAt(index);
                    //拼接
                    str.append(c);
                    index++;
                }
                ls.add(str.toString());

            }

        } while (index < s.length());

        return ls;


    }

    public static List<String> getListString(String sufferExpr) {

        //分隔
        String[] strings = sufferExpr.split(" ");

        return new ArrayList<String>(Arrays.asList(strings));
    }

    //对逆波兰表达式的运算

    //从左到右扫描,将3和4压入栈

    public static int calculate(List<String> ls) {

        Stack<String> stack = new Stack<String>();

        //遍历ls
        for (String s : ls) {

            //使用正则表达式取出数
            if (s.matches("\\d+")) {
                //多位数直接入栈
                stack.push(s);
            } else {
                //运算符,直接pop两个,运算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());

                int res = 0;

                if ("+".equals(s)) {
                    res = num1 + num2;
                } else if ("-".equals(s)) {
                    res = num1 - num2;
                } else if ("*".equals(s)) {
                    res = num1 * num2;
                } else if ("/".equals(s)) {
                    res = num1 / num2;
                } else {
                    throw new RuntimeException("运算符有误!");
                }
                stack.push(res + "");
            }


        }
        return Integer.parseInt(stack.peek());


    }
}

//编写一个类,Operation 可以返回一个运算符对应的优先级
class Operation {

    private static final int ADD = 1;
    private static final int SUB = 1;
    private static final int MUL = 2;
    private static final int DIV = 2;

    //写一个方法返回对应的优先级数字
    public static int getValue(String operation) {
        int result = 0;
        switch (operation) {
            case "+":
                result = ADD;
                break;
            case "-":
                result = SUB;
                break;
            case "*":
                result = MUL;
                break;
            case "/":
                result = DIV;
                break;
            default:
                System.out.println("不存在该运算符");
                break;
        }
        return result;
    }
}